package rsvp.util;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 * Get date utility functions
 * 
 * @author Kuki Szabolcs
 * @version 2003-02-13 - creation date
 */
public class DateUtilities
{
    /** nr of milliseconds in one seccond */
    public static final long F_millisecOfASeccond = 1000;
    /** nr of milliseconds in one minute */
    public static final long F_millisecOfAMinute = 60 * F_millisecOfASeccond;
    /** nr of milliseconds in one hour */
    public static final long F_millisecOfAnHour = 60 * F_millisecOfAMinute;
    /** nr of milliseconds in one day */
    public static final long F_millisecOfADay = 24 * F_millisecOfAnHour;
    /** nr of milliseconds in one week */
    public static final long F_millisecOfAWeek = 7 * F_millisecOfADay;

    /**
     * This is the default format for a date
     */
    public final static String F_dateDefaultFormat = "yyyy-MM-dd";

    /**
     * check if the two dates are pointing to the same day
     * 
     * @param d1
     * @param d2
     * 
     * @return true if they are on the same day
     * 
     * @version 2/27/2003
     */
    public static boolean equalsByDay(Date d1, Date d2)
    {
        if (getYear_forDate(d1) != getYear_forDate(d2))
            return false;
        if (getMonth_forDate(d1) != getMonth_forDate(d2))
            return false;
        if (getDayOfMonth_forDate(d1) != getDayOfMonth_forDate(d2))
            return false;

        return true;
    }

    /**
     * use all default converters to recognize and turn a string into a date
     * 
     * @param sDate
     * 
     * @return a Date
     * @author Eugen 27.09.2002
     * 
     * @throws ParseException
     */
    public static Date convertStringToDate(String sDate) throws ParseException
    {
        Date dActualDate = null;

        if ((sDate == null) || (sDate.equals("")))
        {
            dActualDate = null;
        }
        else
        {

            dActualDate = new java.util.Date(new SimpleDateFormat(
                    F_dateDefaultFormat).parse(sDate).getTime());

            SimpleDateFormat formatter = new SimpleDateFormat(
                    F_dateDefaultFormat);
            formatter.parse(sDate);
        }

        return dActualDate;
    }

    /**
     * parse a date and return the date object, use strong validation on the
     * date
     * 
     * @param sDate
     *            the date in string format
     * @param sFormatType
     *            like yyyy-MM-dd
     * @return a date object
     * 
     * @throws ParseException
     *             if there is an erorr throw an exception even if the date
     *             should be null
     * 
     * @author Kuki Szabolcs
     * @version (time) Feb 9, 2004 3:41:18 PM
     */
    public static Date convertStringToDate_strongValidate(
            String sDate,
            String sFormatType) throws ParseException
    {
        SimpleDateFormat formatter = new SimpleDateFormat(sFormatType);
        formatter.setLenient(false);
        
        Date dActualDate = formatter.parse(sDate);

        if (null == dActualDate)
            throw new ParseException("could not parse date from string: "
                    + sDate, 0);
        return dActualDate;
    }

    /**
     * get short time format: yyyy-mm-dd hh:mm:ss
     * 
     * @param time
     *            a Date
     * 
     * @return a String
     * 
     * @author Kuki Szabolcs
     * @version 2003-02-18
     */
    public static String convertDateToString_yyyyMMdd_hhMMss(Date time)
    {
        if (null == time)
            return "__time is null__";
        else
            return new SimpleDateFormat(F_dateDefaultFormat + " HH:mm:ss")
                    .format(time);
    }

    /**
     * get the input date as string format; if format is null or empty use
     * default format
     * 
     * @param strFormat
     * @param dtDate
     * 
     * @return formated date
     * 
     * @author Tavi
     * @version 2003-11-20
     */
    public static String convertDateToString(String strFormat, Date dtDate)
    {
        if (null == strFormat || "".equals(strFormat))
        {
            strFormat = F_dateDefaultFormat;
        }

        String dCurrentDate = new SimpleDateFormat(strFormat).format(dtDate);

        return dCurrentDate;
    }

    /**
     * return name for a specified month
     * 
     * @param iMonthID
     *            id of month (starts from 0)
     * 
     * @return a String - the name of month
     * 
     * @author Kuki Szabolcs
     * @version 2003-02-13
     */
    public static String infoMonthLongName(Integer iMonthID)
    {
        String sCurrentSelected = infoMonthLongName(iMonthID.intValue());

        return sCurrentSelected;
    }

    /**
     * return name for a specified month
     * 
     * @param iMonth
     *            id of month (starts from 0 to 11 (December))
     * 
     * @return the name of month
     * 
     * @author Kuki Szabolcs
     * @version 2003-02-23
     */
    public static String infoMonthLongName(int iMonth)
    {
        Calendar cal = new GregorianCalendar();
        cal.setTime(new Date());
        cal.set(
            Calendar.MONTH, iMonth);
        cal.set(
            Calendar.DAY_OF_MONTH, 1);

        return infoMonthLongName(cal.getTime());
    }

    /**
     * get max nr of days for month
     * 
     * @param iYear
     * @param iMonthID
     *            an int (0 .. 11)
     * 
     * @return an int
     * 
     * @author Kuki Szabolcs
     * @version 2003-02-13
     */
    public static int infoNrOfDaysForMonth(int iYear, int iMonthID)
    {
        Calendar cal = new GregorianCalendar();
        cal.setTime(new Date());
        cal.set(
            Calendar.YEAR, iYear);
        cal.set(
            Calendar.MONTH, iMonthID + 1);
        cal.set(
            Calendar.DAY_OF_MONTH, 0);

        return cal.get(Calendar.DAY_OF_MONTH);
    }

    /**
     * get max nr of days for month
     * 
     * @param date
     *            a Date
     * 
     * @return an int
     * 
     * @author Kuki Szabolcs
     * @version 2003-02-27
     */
    public static int infoNrOfDaysForMonth(Date date)
    {
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        int iMonthID = getMonth_forDate(date);

        cal.set(
            Calendar.MONTH, iMonthID + 1);
        cal.set(
            Calendar.DAY_OF_MONTH, 0);

        return cal.get(Calendar.DAY_OF_MONTH);
    }

    /**
     * return day of year
     * 
     * @param iYearID
     *            id of year (example: 2003)
     * @param iMonthID
     *            id of month (starts from 0)
     * @param iDayOfMonth
     *            day of month (starting with 1 to 28 or 31)
     * 
     * @return a int
     * 
     * @author Kuki Szabolcs
     * @version 2003-02-13
     */
    public static int infoDayOfYear(
            Integer iYearID,
            Integer iMonthID,
            Integer iDayOfMonth)
    {
        Calendar cal = new GregorianCalendar();
        cal.setTime(new Date());
        cal.set(
            Calendar.YEAR, iYearID.intValue());
        cal.set(
            Calendar.MONTH, iMonthID.intValue());
        cal.set(
            Calendar.DAY_OF_MONTH, iDayOfMonth.intValue());

        return cal.get(Calendar.DAY_OF_YEAR);
    }

    /**
     * return date for year and day of year
     * 
     * @param iYearID
     *            id of year (example: 2003)
     * @param iDOY
     *            day of year (1 .. 366)
     * 
     * @return a Date
     *  
     */
    public static Date getDate(Integer iYearID, Integer iDOY)
    {
        Calendar cal = new GregorianCalendar();
        //		cal.setTime(new Date());
        setTimeOfDayToMidnight(cal);
        cal.set(
            Calendar.YEAR, iYearID.intValue());
        cal.set(
            Calendar.DAY_OF_YEAR, iDOY.intValue());

        return cal.getTime();
    }

    /**
     * return date for year, month, day of month
     * 
     * @param iYear
     * @param iMonthID
     * @param iDayOfMonth
     * 
     * @return a Date
     * 
     * @version 2/27/2003
     */
    public static Date getDate(int iYear, int iMonthID, int iDayOfMonth)
    {
        Calendar cal = new GregorianCalendar();
        //		cal.setTime(new Date());
        setTimeOfDayToMidnight(cal);
        cal.set(
            Calendar.YEAR, iYear);
        cal.set(
            Calendar.MONTH, iMonthID);
        cal.set(
            Calendar.DAY_OF_MONTH, iDayOfMonth);

        Date d = cal.getTime();
        return d;
    }

    /**
     * @param cal
     *            set this calendar to midnight
     * 
     * @author Kuki Szabolcs
     * @version (time) Jan 30, 2004 4:33:07 PM
     */
    private static void setTimeOfDayToMidnight(Calendar cal)
    {
        cal.set(
            Calendar.HOUR_OF_DAY, 0);
        cal.set(
            Calendar.MINUTE, 0);
        cal.set(
            Calendar.SECOND, 0);
        cal.set(
            Calendar.MILLISECOND, 0);
    }

    /**
     * return number of days for a year
     * 
     * @param iYearID
     *            id of year (example: 2003)
     * 
     * @return number of days for specified year
     * 
     * @author Kuki Szabolcs
     * @version 2003-02-13
     */
    public static int infoNrDaysForYear(Integer iYearID)
    {
        Calendar cal = new GregorianCalendar();
        cal.setTime(new Date());
        cal.set(
            Calendar.YEAR, iYearID.intValue() + 1);
        cal.set(
            Calendar.MONTH, 0);
        cal.set(
            Calendar.DAY_OF_MONTH, 0);

        return cal.get(Calendar.DAY_OF_YEAR);
    }

    /**
     * get month id for day of year
     * 
     * @param iYear
     * @param iDayOfYear
     * 
     * @return an int
     * 
     * @author Kuki Szabolcs
     * @version 2003-02-13
     */
    public static String getMonthName_forDayOfYear(
            Integer iYear,
            Integer iDayOfYear)
    {
        Calendar cal = new GregorianCalendar();
        cal.setTime(new Date());
        cal.set(
            Calendar.YEAR, iYear.intValue());
        cal.set(
            Calendar.MONTH, 0);
        cal.set(
            Calendar.DAY_OF_YEAR, iDayOfYear.intValue());

        return infoMonthLongName(new Integer(cal.get(Calendar.MONTH)));
    }

    /**
     * get month day for day of year
     * 
     * @param iYear
     *            an Integer
     * @param iDayOfYear
     *            an Integer
     * 
     * @return an int
     * 
     * @author Kuki Szabolcs
     * @version 2003-02-13
     */
    public static int getDayOfMonth_forDayOfYear(
            Integer iYear,
            Integer iDayOfYear)
    {
        Calendar cal = new GregorianCalendar();
        cal.setTime(new Date());
        cal.set(
            Calendar.YEAR, iYear.intValue());
        cal.set(
            Calendar.MONTH, 0);
        cal.set(
            Calendar.DAY_OF_YEAR, iDayOfYear.intValue());

        return cal.get(Calendar.DAY_OF_MONTH);
    }

    /**
     * get month day for day of year
     * 
     * @param date
     * 
     * @return an int
     * 
     * @author Kuki Szabolcs
     * @version 2003-02-26
     */
    public static int getDayOfMonth_forDate(Date date)
    {
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);

        return cal.get(Calendar.DAY_OF_MONTH);
    }

    /**
     * get month day of week
     * 
     * @param date
     *            a Date
     * 
     * @return an int
     * 
     * @author Kuki Szabolcs
     * @version 2003-02-26
     */
    public static int getDayOfWeek_forDate(Date date)
    {
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        return cal.get(Calendar.DAY_OF_WEEK);
    }

    /**
     * get year for specified date
     * 
     * @param date
     *            a Date
     * 
     * @return an int - the year
     * 
     * @author Kuki Szabolcs
     * @version 2003-02-23
     */
    public static int getYear_forDate(Date date)
    {
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);

        return cal.get(Calendar.YEAR);
    }

    /**
     * get month id (0 .. 11) for specified date
     * 
     * @param date
     *            a Date
     * 
     * @return an int - the monthID (0 .. 11)
     * 
     * @author Kuki Szabolcs
     * @version 2003-02-23
     */
    public static int getMonth_forDate(Date date)
    {
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);

        return cal.get(Calendar.MONTH);
    }

    /**
     * check if the string provided as date is a valid date
     * 
     * @param sDate
     *            a String
     * 
     * @return a boolean
     * 
     * @author Kuki Szabolcs
     * @version 2003-02-13
     */
    public static boolean isValidDate(String sDate)
    {
        boolean bStatus;

        try
        {
            SimpleDateFormat sdf = new SimpleDateFormat(F_dateDefaultFormat);
            sdf.setLenient(false);
            sdf.parse(sDate);
            bStatus = true;
        }
        catch (Exception e)
        {
            bStatus = false;
        }

        return bStatus;
    }

    /**
     * return difference between 2 dates in days, resolution is a day
     * 
     * @param dtEndDate
     * @param dtStartDate
     * 
     * @return dtEndDate - dtStartDate (Example "2003-12-30", "2004-01-01" => 2
     * 
     * @author Kuki Szabolcs
     * @version 2003-03-03
     */
    public static long calcDaysDiff(Date dtEndDate, Date dtStartDate)
    {
        Calendar calStart = new GregorianCalendar();
        calStart.setTime(dtStartDate);
        setTimeOfDayToMidnight(calStart);

        Calendar calEnd = new GregorianCalendar();
        calEnd.setTime(dtEndDate);
        setTimeOfDayToMidnight(calEnd);

        long lTimeD1 = calStart.getTime().getTime();
        long lTimeD2 = calEnd.getTime().getTime();
        double diff = lTimeD2 - lTimeD1;

        return Math.round(diff / F_millisecOfADay);
    }

    /**
     * add some days to a date
     * 
     * @param d1
     *            a Date
     * @param iDaysToAdd
     *            an Integer
     * 
     * @return a Date
     * 
     * @author Kuki Szabolcs
     * @version 2003-03-03
     */
    public static Date calculateAddDaysToDate(Date d1, int iDaysToAdd)
    {
        Calendar cal = new GregorianCalendar();
        cal.setTime(d1);
        cal.add(
            Calendar.DAY_OF_YEAR, iDaysToAdd);

        return cal.getTime();
    }

    /**
     * @param dt
     * @param iWeeksToAdd
     * 
     * @return date with iWeeksToAdd shifted
     * 
     * @author Kuki Szabolcs
     * @version (time) Jan 31, 2004 10:24:04 PM
     */
    public static Date calculateAddWeeksToDate(Date dt, int iWeeksToAdd)
    {
        Calendar cal = new GregorianCalendar();
        cal.setTime(dt);
        cal.add(
            Calendar.WEEK_OF_YEAR, iWeeksToAdd);

        return cal.getTime();
    }
    
    
    /**
     * @param dt
     * @param iMonthsToAdd
     * 
     * @return date with iMonthsToAdd shifted
     * 
     * @author Kuki Szabolcs
     * @version (time) Jan 31, 2004 10:24:04 PM
     */
    public static Date calculateAddMonthsToDate(Date dt, int iMonthsToAdd)
    {
        Calendar cal = new GregorianCalendar();
        cal.setTime(dt);
        cal.add(
            Calendar.MONTH, iMonthsToAdd);

        return cal.getTime();
    }

    /**
     * @param dtCheckWith
     * 
     * @param dtStartDate
     * @param dtEndDate
     * 
     * @return true if dtCheckWith is between <=>start date and end date
     * 
     * @author Kuki Szabolcs
     * @version (time) Feb 5, 2004 5:45:30 PM
     */
    public static boolean isDateBetween(
            Date dtCheckWith,
            Date dtStartDate,
            Date dtEndDate)
    {
        boolean bIsBigger = DateUtilities.calcDaysDiff(
            dtCheckWith, dtStartDate) >= 0;
        boolean bIsSmaller = DateUtilities.calcDaysDiff(
            dtCheckWith, dtEndDate) <= 0;

        return bIsBigger && bIsSmaller;
    }

    /**
     * return month long name for date
     * 
     * @param dt
     * @return example February
     * 
     * @author Kuki Szabolcs
     * @version (time) Jan 31, 2004 11:02:49 AM
     */
    public static String infoMonthLongName(Date dt)
    {
        String sFormat = "MMMMM";
        java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat(sFormat);

        String sCurrentSelected = sdf.format(dt);

        return sCurrentSelected;
    }

}
